local mana_regen_thresh = tonumber(minetest.settings:get("crystal_shattered_regen_threshold")) or 300
local mana_regen_drain = tonumber(minetest.settings:get("crystal_shattered_regen_drain")) or 4

local shattered_to_okay = {
    ["3d_armor_crystal_shattered:helmet_crystal_shattered"] = "3d_armor:helmet_crystal",
    ["3d_armor_crystal_shattered:chestplate_crystal_shattered"] = "3d_armor:chestplate_crystal",
    ["3d_armor_crystal_shattered:leggings_crystal_shattered"] = "3d_armor:leggings_crystal",
    ["3d_armor_crystal_shattered:boots_crystal_shattered"] = "3d_armor:boots_crystal"
}

local okay_to_shattered = {}
for k, v in pairs(shattered_to_okay) do okay_to_shattered[v] = k end

armor:register_armor("3d_armor_crystal_shattered:helmet_crystal_shattered", {
    description = "Shattered " .. S("Crystal Helmet") .. "\n" .. minetest.colorize("red", "hurts to remove!"),
    inventory_image = "3d_armor_crystal_shattered_inv_helmet_crystal_shattered.png",
    groups = {armor_head = 1, armor_heal = 0, armor_use = 800, physics_speed = -0.01, physics_gravity = 0.01},
    armor_groups = {fleshy = 10},
    damage_groups = {cracky = 2, snappy = 3, choppy = 2, crumbly = 1, level = 2}
})
armor:register_armor("3d_armor_crystal_shattered:chestplate_crystal_shattered", {
    description = "Shattered " .. S("Crystal Chestplate") .. "\n" .. minetest.colorize("red", "hurts to remove!"),
    inventory_image = "3d_armor_crystal_shattered_inv_chestplate_crystal_shattered.png",
    groups = {armor_torso = 1, armor_heal = 0, armor_use = 800, physics_speed = -0.04, physics_gravity = 0.04},
    armor_groups = {fleshy = 15},
    damage_groups = {cracky = 2, snappy = 3, choppy = 2, crumbly = 1, level = 2}
})
armor:register_armor("3d_armor_crystal_shattered:leggings_crystal_shattered", {
    description = "Shattered " .. S("Crystal Leggings") .. "\n" .. minetest.colorize("red", "hurts to remove!"),
    inventory_image = "3d_armor_crystal_shattered_inv_leggings_crystal_shattered.png",
    groups = {armor_legs = 1, armor_heal = 0, armor_use = 800, physics_speed = -0.03, physics_gravity = 0.03},
    armor_groups = {fleshy = 15},
    damage_groups = {cracky = 2, snappy = 3, choppy = 2, crumbly = 1, level = 2}
})
armor:register_armor("3d_armor_crystal_shattered:boots_crystal_shattered", {
    description = "Shattered " .. S("Crystal Boots") .. "\n" .. minetest.colorize("red", "hurts to remove!"),
    inventory_image = "3d_armor_crystal_shattered_inv_boots_crystal_shattered.png",
    groups = {armor_feet = 1, armor_heal = 0, armor_use = 800, physics_speed = -0.01, physics_gravity = 0.01},
    armor_groups = {fleshy = 10},
    damage_groups = {cracky = 2, snappy = 3, choppy = 2, crumbly = 1, level = 2}
})
local armors = {"helmet", "chestplate", "leggings", "boots"}

for _, armor in pairs(armors) do
    local itemstring = "3d_armor:" .. armor .. "_crystal"
    local itemstring_shattered = "3d_armor_crystal_shattered:" .. armor .. "_crystal_shattered"
    minetest.register_craft({
        type = "shapeless",
        output = itemstring,
        recipe = {itemstring_shattered, "ethereal:crystal_ingot", "ethereal:etherium_dust"}
    })
    minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv)
        if not itemstack:get_name() == itemstring then return end
        local wear
        for _, v in pairs(old_craft_grid) do if v:get_name() == itemstring_shattered then wear = v:get_wear() end end

        if wear then
            itemstack:set_wear(wear)
            return itemstack
        end

        return nil
    end)
    minetest.register_craft_predict(function(itemstack, player, old_craft_grid, craft_inv)
        if not itemstack:get_name() == itemstring then return end
        local wear
        for _, v in pairs(old_craft_grid) do if v:get_name() == itemstring_shattered then wear = v:get_wear() end end

        if wear then
            itemstack:set_wear(wear)
            return itemstack
        end

        return nil
    end)
end

armor:register_on_damage(function(player, index, stack)
    local itemname = stack:get_name()
    local desc = stack:get_short_description()
    local pl_name = player:get_player_name()
    local chance = 200 -- 1/chance to shatter crystal armor
    if okay_to_shattered[itemname] then
        if math.random(1, chance) == 1 then
            newstack = ItemStack(okay_to_shattered[itemname])
            newstack:set_wear(stack:get_wear())

            minetest.after(0, function()
                local _, armor_inv = armor:get_valid_player(player, "3d_armor")
                local stack = armor_inv:get_stack("armor", index)

                -- check to avoid rare race condition
                if not stack or not stack:get_name() == itemname then return end

                armor:set_inventory_stack(player, index, newstack)
                armor:set_player_armor(player)
            end)

            local words = {"Oops!", "Oh No!", "Whoops!", "*Schink*", "*Crunch*", "*Crack*"}
            minetest.chat_send_player(pl_name, words[math.random(1, #words)] .. " Your " .. desc .. " just shattered!")

            return newstack
        end
    end
end)

armor:register_on_unequip(function(player, index, stack)
    local itemname = stack:get_name()

    if shattered_to_okay[itemname] then
        local toolcaps = {
            full_punch_interval = 0.8,
            max_drop_level = 1,
            groupcaps = {snappy = {times = {[1] = 2.75, [2] = 1.30, [3] = 0.375}, uses = 25, maxlevel = 2}},
            damage_groups = {fleshy = 3}
        }
        player:punch(player, 18, toolcaps)
    end

end)

if mana then
    local regen_slots = {}
    local regen_fun = function(ident, player, pname)
        local tab = regen_slots[pname]
        if not tab then return end

        local _, armor_inv = armor:get_valid_player(player, "3d_armor")

        local pname = player:get_player_name()

        table.shuffle(tab)

        local postponed_actions = {}

        local update_visuals

        for _, slot in ipairs(tab) do
            local stack = armor_inv:get_stack("armor", slot)

            if shattered_to_okay[stack:get_name()] then
                local meta = stack:get_meta()
                local mana_level = meta:get("regen_mana") or 0

                local left_to_regen = (mana_regen_thresh - mana_level)

                local _, _, taken_mana =
                    mana.subtract_up_to(pname, math.min(math.ceil(left_to_regen), mana_regen_drain))
                if taken_mana >= left_to_regen then
                    -- regenerate armor
                    table.insert(postponed_actions, function()
                        newstack = ItemStack(shattered_to_okay[stack:get_name()])
                        newstack:set_wear(stack:get_wear())
                        armor:set_inventory_stack(player, slot, newstack)
                        minetest.chat_send_player(pname, "Your " .. stack:get_short_description() .. " has regenerated!")
                    end)
                    update_visuals = true
                elseif taken_mana > 0 then
                    mana_level = mana_level + taken_mana
                    meta:set_string("regen_mana", tostring(mana_level))
                    table.insert(postponed_actions, function()
                        armor:set_inventory_stack(player, slot, stack)
                    end)
                end
            end
        end

        -- Updating the inventory must be done after we have iterated over the inventory slots,
        -- because updates may alter the table we are iterating over.
        if postponed_actions then for _, fun in pairs(postponed_actions) do fun() end end

        if update_visuals then armor:set_player_armor(player) end
    end

    local armor_change_fun = function(player)
        if not player or not player:is_player() then return end

        local _, armor_inv = armor:get_valid_player(player, "3d_armor")

        local name = player:get_player_name()

        local tab

        for i = 1, 6 do
            local stack = armor_inv:get_stack("armor", i)
            if shattered_to_okay[stack:get_name()] then
                tab = tab or {}
                table.insert(tab, i)
            end
        end

        if tab then
            regen_slots[name] = tab
            mana.register_on_tick("shattered_crystal_regen", name, regen_fun)
        elseif regen_slots[name] then
            regen_slots[name] = nil
            mana.unregister_on_tick("shattered_crystal_regen", name)
        end
    end

    armor:register_on_update(armor_change_fun)

    minetest.register_on_leaveplayer(function(player) regen_slots[player:get_player_name()] = nil end)
end

--- uncomment this to make etherium spawn in desert_stone above the cloud layer (so you can mine it on mars)

--   minetest.register_ore({
--     ore_type       = "scatter",
--     ore            = "ethereal:etherium_ore",
--     wherein        = "default:desert_stone",
--     clust_scarcity = 10 * 10 * 10,
--     clust_num_ores = 5,
--     clust_size     = 3,
--     y_max          = -128,
--     y_min          = -31000,
-- })
